"""
CORS（跨域资源共享）中间件

功能：
- 处理跨域请求，支持预检请求（OPTIONS）
- 基于配置文件动态设置允许的源
- 支持凭据（cookies、授权头）的跨域请求
- 可配置的HTTP方法和头信息
"""

from typing import List, Optional

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response

from app.core import settings


class CustomCORSMiddleware(BaseHTTPMiddleware):
    """
    自定义CORS中间件，提供更灵活的跨域控制

    特性：
    - 支持动态源配置
    - 细粒度的HTTP方法和头控制
    - 预检请求缓存优化
    """

    def __init__(
        self,
        app,
        allow_origins: Optional[List[str]] = None,
        allow_methods: List[str] = None,
        allow_headers: List[str] = None,
        allow_credentials: bool = True,
        max_age: int = 600,
    ):
        super().__init__(app)
        self.allow_origins = allow_origins or settings.CORS_ORIGINS or ["*"]
        self.allow_methods = allow_methods or ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]
        self.allow_headers = allow_headers or ["*"]
        self.allow_credentials = allow_credentials
        self.max_age = max_age

    async def dispatch(self, request: Request, call_next) -> Response:
        """
        处理CORS请求

        Args:
            request: HTTP请求对象
            call_next: 调用链中的下一个处理函数

        Returns:
            Response: 处理后的HTTP响应
        """
        # 处理预检请求（OPTIONS）
        if request.method == "OPTIONS" and "Access-Control-Request-Method" in request.headers:
            return await self._handle_preflight_request(request)

        # 处理普通请求
        response = await call_next(request)
        return self._add_cors_headers(request, response)

    async def _handle_preflight_request(self, request: Request) -> Response:
        """
        处理预检请求（OPTIONS）

        Args:
            request: OPTIONS请求对象

        Returns:
            Response: 预检响应
        """
        response = Response(content="", status_code=200, headers=self._build_cors_headers(request))
        return response

    def _add_cors_headers(self, request: Request, response: Response) -> Response:
        """
        为响应添加CORS头信息

        Args:
            request: 原始请求对象
            response: 原始响应对象

        Returns:
            Response: 添加了CORS头的响应
        """
        origin = request.headers.get("Origin")
        if origin and self._is_origin_allowed(origin):
            cors_headers = self._build_cors_headers(request)
            for header, value in cors_headers.items():
                response.headers[header] = value
        return response

    def _build_cors_headers(self, request: Request) -> dict:
        """
        构建CORS头信息

        Args:
            request: 请求对象

        Returns:
            dict: CORS头信息字典
        """
        origin = request.headers.get("Origin", "")
        headers = {}

        if self._is_origin_allowed(origin):
            headers["Access-Control-Allow-Origin"] = origin
            if self.allow_credentials:
                headers["Access-Control-Allow-Credentials"] = "true"

        # 预检请求的特殊头
        if request.method == "OPTIONS":
            headers["Access-Control-Allow-Methods"] = ", ".join(self.allow_methods)
            headers["Access-Control-Allow-Headers"] = ", ".join(self.allow_headers)
            headers["Access-Control-Max-Age"] = str(self.max_age)

        return headers

    def _is_origin_allowed(self, origin: str) -> bool:
        """
        检查源是否被允许

        Args:
            origin: 请求源

        Returns:
            bool: 是否允许该源
        """
        if "*" in self.allow_origins:
            return True
        return origin in self.allow_origins


def setup_cors_middleware(app: FastAPI) -> None:
    """
    设置标准CORS中间件（推荐使用）

    Args:
        app: FastAPI应用实例
    """
    # 从配置中获取允许的源，如果为空则允许所有源（仅开发环境）
    allow_origins = settings.CORS_ORIGINS or ["*"]

    app.add_middleware(
        CORSMiddleware,
        allow_origins=allow_origins,
        allow_credentials=True,
        allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
        allow_headers=["*"],
        max_age=600,
    )
